---
title: Using old React versions
description: Guide for using assistant-ui with older React versions (18, 17, 16)
---

import { Callout } from "fumadocs-ui/components/callout";

<Callout type="warning" title="Older React Versions">
  Older React versions are not continuously tested. If you encounter any issues
  with integration, please contact us for help by joining our
  [Discord](https://discord.gg/S9dwgCNEFs).
</Callout>

This guide provides instructions for configuring assistant-ui to work with React 18 or older versions.

## React 18

If you're using React 18, you need to update the shadcn/ui components to work with `forwardRef`. Specifically, you need to modify the Button component.

### Updating the Button Component

Navigate to your button component file (typically `/components/ui/button.tsx`) and wrap the Button component with `forwardRef`:

```tsx
// Before
function Button({
  className,
  variant,
  size,
  asChild = false,
  ...props
}: React.ComponentProps<"button"> &
  VariantProps<typeof buttonVariants> & {
    asChild?: boolean;
  }) {
  const Comp = asChild ? Slot : "button";

  return (
    <Comp
      data-slot="button"
      className={cn(buttonVariants({ variant, size, className }))}
      {...props}
    />
  );
}

// After
const Button = React.forwardRef<
  HTMLButtonElement,
  React.ComponentProps<"button"> &
    VariantProps<typeof buttonVariants> & {
      asChild?: boolean;
    }
>(({ className, variant, size, asChild = false, ...props }, ref) => {
  const Comp = asChild ? Slot : "button";

  return (
    <Comp
      data-slot="button"
      className={cn(buttonVariants({ variant, size, className }))}
      ref={ref}
      {...props}
    />
  );
});
Button.displayName = "Button";
```

**Note:** If you're using a lower React version (17 or 16), you'll also need to follow the instructions for that version.

## React 17

For React 17 compatibility, in addition to the modifications outlined for React 18, you must also include a polyfill for the `useSyncExternalStore` hook (utilized by zustand).

### Patching Zustand with patch-package

Since the assistant-ui uses zustand internally, which depends on `useSyncExternalStore`, you'll need to patch the zustand package directly:

1. Install the required packages:

```bash
npm install use-sync-external-store patch-package
# or
yarn add use-sync-external-store patch-package
```

2. Add a postinstall script to your package.json:

```json
{
  "scripts": {
    "postinstall": "patch-package"
  }
}
```

3. You'll want to follow the instructions in [patch-package](https://github.com/ds300/patch-package), by first making changes to the files of a particular package in your node_modules folder, then running either `yarn patch-package package-name` or `npx patch-package package-name`. You'll need a patch for zustand - within `node_modules/zustand`, open `zustand/react.js` and make the following code changes:

```diff
diff --git a/node_modules/zustand/react.js b/node_modules/zustand/react.js
index 7599cfb..64530a8 100644
--- a/node_modules/zustand/react.js
+++ b/node_modules/zustand/react.js
@@ -1,6 +1,6 @@
 'use strict';

-var React = require('react');
+var React = require('use-sync-external-store/shim');
 var vanilla = require('zustand/vanilla');

 const identity = (arg) => arg;
@@ -10,7 +10,7 @@ function useStore(api, selector = identity) {
     () => selector(api.getState()),
     () => selector(api.getInitialState())
   );
-  React.useDebugValue(slice);
+  //React.useDebugValue(slice);
   return slice;
 }
 const createImpl = (createState) => {

This patch replaces the React import in zustand with the polyfill from `use-sync-external-store/shim` and comments out the `useDebugValue` call which isn't needed.

You should then run the patch-package command `yarn patch-package zustand` or `npx patch-package zustand` which should create a `patches` folder with a zustand patch file similar looking to this:

```diff
diff --git a/node_modules/zustand/react.js b/node_modules/zustand/react.js
index 7599cfb..64530a8 100644
--- a/node_modules/zustand/react.js
+++ b/node_modules/zustand/react.js
@@ -1,6 +1,6 @@
 'use strict';

-var React = require('react');
+var React = require('use-sync-external-store/shim');
 var vanilla = require('zustand/vanilla');

 const identity = (arg) => arg;
@@ -10,7 +10,7 @@ function useStore(api, selector = identity) {
     () => selector(api.getState()),
     () => selector(api.getInitialState())
   );
-  React.useDebugValue(slice);
+  //React.useDebugValue(slice);
   return slice;
 }
 const createImpl = (createState) => {
```

4. You may also need to apply the same patches within `node_modules/@assistant-ui/react/` and possibly a nested dependency patch for `node_modules/@assistant-ui/react/node_modules/zustand`. Look for instances of `React.useSyncExternalStore` and replace with `{ useSyncExternalStore } from "use-sync-external-store/shim";` and comment out any `useDebugValue` calls. Finally, you may need to patch `useId` from React, so within `node_modules/@assistant-ui/react/dist/runtimes/remote-thread-list/RemoteThreadListThreadListRuntimeCore.js`, change the following:

```diff
-import { Fragment, useEffect, useId } from "react";
+import { Fragment, useEffect, useRef } from "react";
 import { create } from "zustand";
 import { AssistantMessageStream } from "assistant-stream";
 import { RuntimeAdapterProvider } from "../adapters/RuntimeAdapterProvider.js";
 import { jsx } from "react/jsx-runtime";
+
+// PATCH-PACKAGE: Polyfill for useId if not available in React 16
+let useId;
+try {
+  // Try to use React's useId if available
+  useId = require("react").useId;
+} catch (e) {}
+if (!useId) {
+  // Fallback polyfill
+  let globalId = 0;
+  useId = function() {
+    const idRef = useRef();
+    if (!idRef.current) {
+      globalId++;
+      idRef.current = `uid-${globalId}`;
+    }
+    return idRef.current;
+  };
+}
```

5. Run the postinstall script to apply the patches:

```bash
npm run postinstall
# or
yarn postinstall
```

This patch replaces the React import in zustand with the polyfill from `use-sync-external-store/shim` and comments out the `useDebugValue` call which isn't needed.

**Note:** If you're using React 16, you'll also need to follow the instructions for that version.

## React 16

<Callout type="info" title="Incomplete Section">
  This section is incomplete and contributions are welcome. If you're using
  React 16 and have successfully integrated assistant-ui, please consider
  contributing to this documentation.
</Callout>

For React 16 compatibility, you need to apply all the steps for **React 18** and **React 17** above.

## Additional Resources

If you encounter any issues with React compatibility, please:

1. Check that all required dependencies are installed
2. Ensure your component modifications are correctly implemented
3. Join our [Discord](https://discord.gg/S9dwgCNEFs) community for direct support
